package com.log.enhance.filter;

import com.alibaba.fastjson.JSONObject;
import com.log.enhance.aspect.LogThreadContext;
import com.log.enhance.config.properties.EnableFromAndToProperty;
import com.log.enhance.constant.LogPluginConstant;
import com.log.enhance.interceptor.FeignRequestInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.UUID;

/**
 * 添加全局traceId、from、to的过滤器(需要在启动类上使用注解 @EnableLogChain 开启该过滤器才能生效)
 *
 * @author Mr_wenpan@163.com 2021/05/30 22:28
 */
@Slf4j
public class AddTraceIdFilter implements Filter {

    /**
     * 该日志是来自于哪个服务的
     */
    String fromWhichService;

    @Value("${spring.application.name:unkown-service}")
    String toWhichService;

    @Autowired
    FeignRequestInterceptor feignRequestInterceptor;

    @Autowired(required = false)
    private EnableFromAndToProperty enableFromAndToProperty;

    private static final String FROM = "from";
    private static final String TO = "to";

    @Override
    public void init(FilterConfig filterConfig) {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        String traceId = request.getHeader(LogPluginConstant.TRACEID);

        if (StringUtils.isBlank(traceId)) {
            traceId = (String) request.getAttribute(LogPluginConstant.TRACEID);
        }
        if (StringUtils.isBlank(traceId)) {
            traceId = UUID.randomUUID().toString();
            request.setAttribute(LogPluginConstant.TRACEID, traceId);
            log.info("创建traceId: {}", traceId);
        }

        // 放入到MDC并给响应头上添加一个traceId属性（可以不添加）
        MDC.put(LogPluginConstant.TRACEID, traceId);
        resp.addHeader(LogPluginConstant.TRACEID, traceId);

        // 只有在配置文件中显示的开启了from和to的打印，才打印日志from和to
        if (enableFromAndToProperty != null && enableFromAndToProperty.getEnableLogSource()) {
            putFromAndToJson2MDC(request);
        }

        try {
            // 放行，等过滤链返回后需要清除MDC和threadLocal中的内容防止内存泄漏
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            // 防止内存泄漏和线程池线程复用
            MDC.remove(LogPluginConstant.TRACEID);
            MDC.remove(LogPluginConstant.FROM_AND_TO_JSON);
            MDC.remove(LogPluginConstant.LOG_JSON);
            MDC.clear();
            // 移除掉当前线程内的threadlocal中的Map中的value，防止内存泄漏
            LogThreadContext.LOG_THREAD_CONTEXT.remove();
        }

    }

    /**
     * 将此次请求从哪个服务请求过来的，到那个服务的json字符串放入到MDC
     */
    private void putFromAndToJson2MDC(HttpServletRequest request) {
        JSONObject jsonObject = new JSONObject();
        String from = request.getHeader(LogPluginConstant.FROM_WHICH_SERVICE);
        if (StringUtils.isBlank(from)) {
            from = MDC.get(LogPluginConstant.FROM_WHICH_SERVICE);
        }
        if (StringUtils.isBlank(from)) {
            from = (String) request.getAttribute(LogPluginConstant.FROM_WHICH_SERVICE);
        }
        if (StringUtils.isBlank(from)) {
            fromWhichService = LogPluginConstant.DEFAULT_SOURCE;
        } else {
            fromWhichService = from;
        }
        jsonObject.put(FROM, fromWhichService);
        jsonObject.put(TO, toWhichService);
        MDC.put(LogPluginConstant.FROM_AND_TO_JSON, jsonObject.toJSONString());
        MDC.put(LogPluginConstant.TO_WHICH_SERVICE, toWhichService);
    }

    @Override
    public void destroy() {

    }
}
